#!/usr/bin/python3
# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: t -*-

import abc
import enum
from ._egress import EgressIpHost
from ._egress import EgressIpService
from ._egress import EgressDomainHost
from ._egress import EgressDomainService


class PluginType(enum.Enum):
    UPLINK = "uplink"
    SUBNET = "subordinate-network"
    PEERNET = "peer-network"
    OBCONN = "outbound-connection"
    GUESTNET = "guest-network"


class PluginObjectSource(enum.Enum):
    LIB = "lib"
    CACHE = "cache"
    CFG = "cfg"


class PluginBase(abc.ABC):

    def __init__(self, plugin_id, plugin_description):
        self._id = str(plugin_id)
        self._desc = str(plugin_description)

    @property
    def plugin_id(self):
        return self._id

    @property
    def plugin_description(self):
        return self._desc

    @property
    def plugin_type(self):
        if isinstance(self, UpLinkPluginBase):
            return PluginType.UPLINK
        elif isinstance(self, SubNetPluginBase):
            return PluginType.SUBNET
        elif isinstance(self, PeerNetPluginBase):
            return PluginType.PEERNET
        elif isinstance(self, ObConnPluginBase):
            return PluginType.OBCONN
        elif isinstance(self, GuestNetPluginBase):
            return PluginType.GUESTNET
        else:
            assert False

    @property
    def need_temp_directory(self):
        return False

    @property
    def need_data_directory(self):
        return False


class UpLinkPluginBase(PluginBase):

    class Context(abc.ABC):

        def __init__(self, param):
            self.LIB_UPLINK_DIR = param.LIB_UPLINK_DIR
            self.CFG_UPLINK_DIR = param.CFG_UPLINK_DIR

        @abc.abstractmethod
        def add_uplink(self, uplink_object):
            pass

        @abc.abstractmethod
        def remove_uplink(self, uplink_uuid):
            pass

    def __init__(self, plugin_id, plugin_description):
        super().__init__(plugin_id, plugin_description)
        self._context = None

    def set_context(self, context):
        assert isinstance(context, self.Context)
        self._context = context

    @abc.abstractmethod
    async def on_event(self, event):
        pass


class SubNetPluginBase(PluginBase):

    class Context(abc.ABC):
        pass

    def __init__(self, plugin_id, plugin_description):
        super().__init__(plugin_id, plugin_description)
        self._context = None

    def set_context(self, context):
        assert isinstance(context, self.Context)
        self._context = context

    @abc.abstractmethod
    async def on_event(self, event):
        pass


class PeerNetPluginBase(PluginBase):

    class Context(abc.ABC):
        pass

    def __init__(self, plugin_id, plugin_description):
        super().__init__(plugin_id, plugin_description)
        self._context = None

    def set_context(self, context):
        assert isinstance(context, self.Context)
        self._context = context

    @abc.abstractmethod
    async def on_event(self, event):
        pass


class ObConnPluginBase(PluginBase):

    class Context(abc.ABC):

        @property
        @abc.abstractmethod
        def LIB_OBCONN_DIR(self):
            pass

        @property
        def CACHE_OBCONN_DIR(self):
            pass

        @property
        def CFG_OBCONN_DIR(self):
            pass

        @property
        @abc.abstractmethod
        def settings(self):
            pass

        @abc.abstractmethod
        def is_in_gateway(self):
            pass

        @abc.abstractmethod
        async def on_obconn_available(self, uuid, is_in_gateway, data):
            pass

        @abc.abstractmethod
        async def on_obconn_unavailable(self, uuid):
            pass

    def __init__(self, plugin_id, plugin_description):
        super().__init__(plugin_id, plugin_description)
        self._context = None

    def set_context(self, context):
        assert isinstance(context, self.Context)
        self._context = context

    async def on_init(self):
        pass

    async def on_egress_changed(self, egresses, geolocation):
        pass


class GuestNetPluginBase(PluginBase):

    class Context(abc.ABC):
        pass

    def __init__(self, plugin_id, plugin_description):
        super().__init__(plugin_id, plugin_description)
        self._context = None

    def set_context(self, context):
        assert isinstance(context, self.Context)
        self._context = context

    @abc.abstractmethod
    async def on_event(self, event):
        pass
